//
//  Primitive.hpp
//  RayTracer
//
//  Created by 俞云康 on 4/13/16.
//  Copyright © 2016 yushroom. All rights reserved.
//

#ifndef Primitive_hpp
#define Primitive_hpp

#include "AABB.hpp"
#include "Ray.hpp"
#include "HitInfo.hpp"
#include "Light.hpp"
#include "Material.hpp"
#include "Shape.hpp"
#include "Light.hpp"
#include "TriangleMesh.hpp"

struct KdAccelNode;
struct BoundEdge;
class Params;

class Primitive {
public:
    virtual ~Primitive() = default;
    virtual AABB worldBounds() const = 0;
    virtual bool intersect(const Ray& , HitInfo *) const = 0;
    virtual bool intersect(const Ray&) const = 0;
};

class GeometricPrimitive : public Primitive {
private:
    shared_ptr<Shape> mShape;
    shared_ptr<Material> mMaerial;
    shared_ptr<AreaLight> mAreaLight;
    
public:
    GeometricPrimitive(const shared_ptr<Shape> &shape,
                       const shared_ptr<Material> &material,
                       const shared_ptr<AreaLight> &areaLight)
    : mShape(shape), mMaerial(material), mAreaLight(areaLight) {}
    
    //GeometricPrimitive(const shared_ptr<Triangle> &triangle,
    //                   const shared_ptr<Material> &material,
    //                   const shared_ptr<AreaLight> &areaLight)
    //: mShape(triangle), mMaerial(material), mAreaLight(areaLight) {
    //    triangle->boundingBox.expandBy(triangle->mesh->positions[triangle->idx[0]]);
    //    triangle->boundingBox.expandBy(triangle->mesh->positions[triangle->idx[1]]);
    //    triangle->boundingBox.expandBy(triangle->mesh->positions[triangle->idx[2]]);
    //}
    
    static shared_ptr<GeometricPrimitive> create(const Params& params);
    
    virtual AABB worldBounds() const override {
        return mShape->boundingBox;
    }
    virtual bool intersect(const Ray& ray, HitInfo * hit) const override {
        //float tHit;
        if (!mShape->intersect(ray, hit))
            return false;
        hit->primitive = this;
        hit->material = mMaerial;
        return true;
    }
    virtual bool intersect(const Ray& ray) const override {
        return mShape->intersect(ray);
    }
    bool isEmitter() const {
        return getAreaLight() != nullptr;
    }
    const AreaLight* getAreaLight() const {
        return mAreaLight.get();
    }
	shared_ptr<AreaLight> getAreaLightShared() {
		return mAreaLight;
	}
    virtual const Material* getMaterial() const {
        return mMaerial.get();
    }
    
    friend class AreaLight;
};


#endif /* Primitive_hpp */
